/******************************************************************************************************************
* File:ECSMonitor.java
* Course: 17655
* Project: Assignment A3
* Copyright: Copyright (c) 2009 Carnegie Mellon University
* Versions:
*	1.0 March 2009 - Initial rewrite of original assignment 3 (ajl).
*
* Description:
*
* This class monitors the environmental control systems that control museum temperature and humidity. In addition to
* monitoring the temperature and humidity, the ECSMonitor also allows a user to set the humidity and temperature
* ranges to be maintained. If temperatures exceed those limits over/under alarm indicators are triggered.
*
* Parameters: IP address of the event manager (on command line). If blank, it is assumed that the event manager is
* on the local machine.
*
* Internal Methods:
*	static private void Heater(EventManagerInterface ei, boolean ON )
*	static private void Chiller(EventManagerInterface ei, boolean ON )
*	static private void Humidifier(EventManagerInterface ei, boolean ON )
*	static private void Dehumidifier(EventManagerInterface ei, boolean ON )
*
******************************************************************************************************************/
package Alarms;

import java.util.HashMap;
import java.util.Map.Entry;
import EventPackage.*;

public class AlarmMonitor extends ParticipantThread
{
	private HashMap<String, AlarmIndicator> alarms = new HashMap<String, AlarmIndicator>();	// Alarm set with Indicators
	private int confirmationAlarmRegistrationEvtId = -8;	
	private int confirmationArmDisarmEvtId = -7;	
	private int emergencyEvtId = 6;	
	private int normalityEvtId = 12;	
	private int monitorPingEvtId = 11;		
	private int monitorPingReturnEvtId = -11;		
	private int armDisarmEvtId = 9;	
	private int alarmArmDisarmFailureEvtId = 10;	
	private String separator = "-@-";
	private int indicatorsXpos = 700; 
	private int indicatorsYpos = 200; 
	private int indicatorsHeight = 150;
	private int indicatorsWidth = 180;
	private int alarmCount = 0;
	private int sprinklerTimerID = 14;
	
	public AlarmMonitor(String name, int Xpos, int Ypos, int mwHeight, int mwWidthString, String[] args, int subSystemHaltEnvId) {
		super();
		
		this.name = name;
		
		setParameters(name, Xpos, Ypos, mwHeight, mwWidthString, args, subSystemHaltEnvId, name);
	}

	public void Halt()
	{
		mw.WriteMessage( "***HALT MESSAGE RECEIVED - SHUTTING DOWN SYSTEM***" );

		// Here we create the stop event.

		Event evt;

		evt = new Event( (int) 91, "XXX" );

		// Here we send the event to the event manager.

		try
		{
			em.SendEvent( evt );

		} // try

		catch (Exception e)
		{
			System.out.println("Error sending halt message:: " + e);

		} // catch

	} // Halt
	
	public void CompleteHalt()
	{
		mw.WriteMessage( "***HALT MESSAGE RECEIVED - SHUTTING DOWN THE ENTIRE SYSTEM***" );

		// Here we create the stop event.

		Event evt;

		evt = new Event( (int) 99, "XXX" );

		// Here we send the event to the event manager.

		try
		{
			em.SendEvent( evt );

		} // try

		catch (Exception e)
		{
			System.out.println("Error sending halt message:: " + e);

		} // catch

	} // Halt

	@Override
	protected void beforeLooping() {
		// Call for participant alarms
		postEvent(monitorPingEvtId);
	}

	@Override
	protected void initialPostPhase() {
		// TODO Auto-generated method stub
		
	}

	@Override
	protected void handlePhase() {
		if (Evt.GetEventId() == monitorPingReturnEvtId)
		{
			registerAlarm();
		} // if
		
		if (Evt.GetEventId() == confirmationAlarmRegistrationEvtId)
		{
			alarmRegisteredWithController();
		} // if
		
		if (Evt.GetEventId() == alarmArmDisarmFailureEvtId)
		{
			ArmDisarmFailure();
		} // if
		
		if ( Evt.GetEventId() == confirmationArmDisarmEvtId )
		{
			String evtMsg = Evt.GetMessage();
			String alarmId = evtMsg.substring(0, evtMsg.length() - 1);
			char evtCommand = evtMsg.charAt(evtMsg.length() - 1);
			
			if (evtCommand == '1') {
				alarms.get(alarmId).setStatus(1);
				mw.WriteMessage("Arming Alarm: [" + alarmId + "] Armed");
			} else {
				alarms.get(alarmId).setStatus(0);
				mw.WriteMessage("Arming Alarm: [" + alarmId + "] Disarmed");
			}
		} // if
		
		if ( Evt.GetEventId() == normalityEvtId )
		{
			String evtMsg = Evt.GetMessage();
			String alarmId = evtMsg;

			alarms.get(alarmId).setStatus(1);
			mw.WriteMessage("Arming Alarm: [" + alarmId + "] Status: armed / normal");
		} // if

		if ( Evt.GetEventId() == emergencyEvtId )
		{
			String evtMsg = Evt.GetMessage();
			String alarmId = evtMsg;

			alarms.get(alarmId).setStatus(2);
			mw.WriteMessage("Alarm: [" + alarmId + "] Status: !!! EMERGENCY !!!");
		} // if
		
		if( Evt.GetEventId() == sprinklerTimerID ){
			mw.WriteMessage("Sprinkler timer has started! Less than 15 seconds to deactivate!");
		}
	}
	
	private void ArmDisarmFailure() {
		String evtMsg = Evt.GetMessage();
		String alarmId = evtMsg.substring(0, evtMsg.length() - 1);
		char evtCommand = evtMsg.charAt(evtMsg.length() - 1);
				
		if (evtCommand == '1') {
			mw.WriteMessage("  FAILURE:: Alarm: [" + alarmId + "] failed to arm");
		} else {
			mw.WriteMessage("  FAILURE:: Alarm: [" + alarmId + "] failed to disarm");
		}
	}
	
	private void registerAlarm() {
		String[] evtMsg = Evt.GetMessage().split(separator);
		String alarmId = evtMsg[0];
		String alarmName = evtMsg[1];
		int alarmStatus = Integer.parseInt(evtMsg[2]);
		
		if (! alarms.containsKey(alarmId)) {
			
			AlarmIndicator indicator = new AlarmIndicator(alarmName, indicatorsXpos + (indicatorsWidth * alarmCount) + 10, indicatorsYpos, indicatorsHeight, indicatorsWidth);
			indicator.setStatus(alarmStatus);
			
			alarmCount ++;
			mw.WriteMessage("Registering Alarm: [" + alarmId + "]");
			
			alarms.put(alarmId, indicator);
		}
	}
	
	private void alarmRegisteredWithController() {
		String[] evtMsg = Evt.GetMessage().split(separator);
		String alarmId = evtMsg[0];
		
		if (alarms.containsKey(alarmId)) {
			
			AlarmIndicator indicator = alarms.get(alarmId);
			indicator.setStatus(0);
			
			mw.WriteMessage("Alarm: [" + alarmId + "] Found a controller");
		}
	}
	
	public void arm() {
		mw.WriteMessage("Arming ...");
		postEvent(armDisarmEvtId, "1");
	}

	public void disArm() {
		mw.WriteMessage("Disarming ...");
		postEvent(armDisarmEvtId, "0");
	}

	public void reset() {
		
	}

	@Override
	protected void finalPostPhase() {
		// TODO Auto-generated method stub
		
	}

	@Override
	protected void customHalt() {
		for (Entry<String, AlarmIndicator> alarmEntry : alarms.entrySet()) {
			alarmEntry.getValue().dispose();
		}
	}

} // ECSMonitor